package cn.exrick.xboot.modules.app.controller;

import cn.exrick.xboot.common.constant.CommonConstant;
import cn.exrick.xboot.common.constant.SecurityConstant;
import cn.exrick.xboot.common.jiuqiCommon.callAPIUtil.CallSMSservice;
import cn.exrick.xboot.common.qywxCode.CreateRandomNums;
import cn.exrick.xboot.common.qywxCode.Security.service.MyUserDetailsService;
import cn.exrick.xboot.common.utils.ResultUtil;
import cn.exrick.xboot.common.utils.SecurityUtil;
import cn.exrick.xboot.common.utils.SpringContextUtil;
import cn.exrick.xboot.common.vo.Result;
import cn.exrick.xboot.common.vo.TokenUser;
import cn.exrick.xboot.config.redis.RedisRepository;
import cn.exrick.xboot.modules.AppUtils.entity.AppAutoUpdate;
import cn.exrick.xboot.modules.AppUtils.service.AppAutoUpdateService;
import cn.exrick.xboot.modules.ApprovalInfo.serviceimpl.IApprovalInfoServiceImpl;
import cn.exrick.xboot.modules.base.dao.UserDao;
import cn.exrick.xboot.modules.base.entity.User;
import cn.exrick.xboot.modules.base.service.UserService;
import cn.exrick.xboot.modules.base.serviceimpl.mybatis.IUserRoleServiceImpl;
import cn.exrick.xboot.modules.callApi.entity.SMS;
import cn.hutool.core.util.StrUtil;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author    : LiYuanzhuo
 * description: app端登录接口
 * create time: 2019/9/4 15:51
 */
@Slf4j
@RestController
@Api(description = "app端登录接口")
@RequestMapping(value = "/hnPortalApp")

public class AppLogin {
    @Autowired
    private UserService userService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisRepository redisRepository;
    @Autowired
    private CallSMSservice callSMSservice;
    @Autowired
    private IUserRoleServiceImpl iUserRoleService;
    @Resource
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private UserDao userDao;


    @Value("${xboot.tokenExpireTime}")
    private Integer tokenExpireTime;

    @Value("${xboot.saveLoginTime}")
    private Integer saveLoginTime;

    @Value("${xboot.token.storePerms}")
    private Boolean storePerms;

    @Value("${portal.frontUrl}")
    private String frontUrl;
    @Autowired
    private IApprovalInfoServiceImpl iApprovalInfoService;

    @Autowired
    private AppAutoUpdateService appAutoUpdateService;
    @RequestMapping(value = "/autoLogin",method = RequestMethod.POST)
    public Result<Object> autoLogin(@RequestParam String username,HttpServletRequest request){

        String headerToken = request.getHeader(SecurityConstant.HEADER);
        String v = stringRedisTemplate.opsForValue().get(SecurityConstant.APP_TOKEN_PRE + headerToken);
        if (v == null || v == ""){
            return new ResultUtil<>().setErrorMsg(401,"登录已失效，请重新登录!");
        }
        /*//判断用户是否已经处于登录状态
        String appLoginState = redisRepository.get(CommonConstant.APP_LOGIN_TOKEN + username);
        if (appLoginState == null) {
            return new ResultUtil<>().setErrorMsg("登录已失效，请重新登录!");
        }*/

        //验证用户名
        User user = userService.findByUsername(username);
        if (user.getStatus().equals(CommonConstant.USER_STATUS_LOCK)){
            return new ResultUtil<Object>().setErrorMsg("该用户已经被禁用！请联系管理员！");
        }
        //是否是审批员
        Boolean isRoleApproval;
        isRoleApproval = iUserRoleService.getApprovalRole(user);
        if (isRoleApproval){
            iApprovalInfoService.sendApprovalInfoToAPP(username);
        }

        /**
         * njp 20200119 add
         * 新增app登录成功后返回自动更新平台地址
         * begin
         */
        AppAutoUpdate type = appAutoUpdateService.findByType("jiuqi");
        if(type==null){
            type=new AppAutoUpdate();
            type.setUpdateUrl("http://47.92.27.141:8899");
        }
        /**
         * njp 20200119 add
         * 新增app登录成功后返回自动更新平台地址
         * end
         */

        Map map = new HashMap();
        map.put("accessToken",headerToken);
        map.put("username",user.getUsername());
        map.put("idCard",user.getIdcard());
        map.put("idcardEncryption",user.getIdcardEncryption());
        map.put("IS_ROLE_APPROVAL",isRoleApproval);
        map.put("nickName",user.getNickName());
        map.put("autoUpdateUrl",type.getUpdateUrl());
        map.put("portalFrontUrl",frontUrl);
        return new ResultUtil<>().setData(map,"登录成功");
    }

    @RequestMapping(value = "/appLogin",method = RequestMethod.POST)
    @ApiOperation(value = "appLogin")
    public Result<Object> appLogin(@RequestParam String username, @RequestParam String code, HttpServletRequest httpRequest){
        log.info("app使用用户名密码登录接受到的参数username{},code{} " , username ,code);
        if (username == null || username == "") {
            return new ResultUtil<>().setErrorMsg("用户名不能为空！");
        }

        //验证用户名与密码
        User user = userService.findByUsername(username);
        if (user == null) {
            user = userService.findByMobile(username);
            if (user == null){
                return new ResultUtil<Object>().setErrorMsg("用户不存在");
            }
           List<User> userList= userDao.findByMobile(username);
            if (userList.size()>1){
                return new ResultUtil<Object>().setErrorMsg("该手机号绑定了多个账户，请使用身份证号登录！");
            }

        }

        if (user.getStatus().equals(CommonConstant.USER_STATUS_LOCK)){
            return new ResultUtil<Object>().setErrorMsg("该用户已经被禁用！请联系管理员！");
        }

        redisTemplate = (RedisTemplate) SpringContextUtil.getBean("redisTemplate");
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);

        if (code == null || code == "") {
            return new ResultUtil<>().setErrorMsg("用户首次登录，短信验证码不能为空!");
        }
        //验证验证码
        if (!redisRepository.exists(CommonConstant.APP_CMS_CODE + user.getUsername())){
            return new ResultUtil<>().setErrorMsg("验证码已失效，请重新获取!");
        }

        String cmsCode = redisRepository.get(CommonConstant.APP_CMS_CODE + user.getUsername());

        if (!code.equals(cmsCode) ){
            return new ResultUtil<>().setErrorMsg("请输入正确的验证码!");
        }else {
            //验证成功，删除验证码
            redisTemplate.delete(CommonConstant.APP_CMS_CODE + user.getUsername());
        }


        String token = UUID.randomUUID().toString().replace("-", "");

        SecurityUtil securityUtil = new SecurityUtil();
        //用户权限放置
        List<GrantedAuthority> authorities = securityUtil.getCurrUserPerms(user.getUsername());

        List<String> list = new ArrayList<>();
        for(GrantedAuthority g : authorities){
            list.add(g.getAuthority());
        }
        TokenUser users = new TokenUser(user.getUsername(), list, false);

        UserDetails userDetails = myUserDetailsService.loadUserByUsername(user);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 单点登录 之前的token失效
        String oldToken = stringRedisTemplate.opsForValue().get(CommonConstant.APP_LOGIN_TOKEN + user.getUsername());
        if(StrUtil.isNotBlank(oldToken)){
            redisTemplate.delete(SecurityConstant.APP_TOKEN_PRE + oldToken);
        }

        redisTemplate.opsForValue().set(CommonConstant.APP_LOGIN_TOKEN + user.getUsername(), token, 30, TimeUnit.DAYS);
        redisTemplate.opsForValue().set(SecurityConstant.APP_TOKEN_PRE + token, new Gson().toJson(users), 30, TimeUnit.DAYS);

        /**
         * njp 20200119 add
         * 新增app登录成功后返回自动更新平台地址
         * begin
         */
        AppAutoUpdate type = appAutoUpdateService.findByType("jiuqi");
        if(type==null){
            type=new AppAutoUpdate();
            type.setUpdateUrl("http://47.92.27.141:8899");
        }
        /**
         * njp 20200119 add
         * 新增app登录成功后返回自动更新平台地址
         * end
         */

        Map map = new HashMap();

        //是否是审批员
        Boolean isRoleApproval;
        isRoleApproval = iUserRoleService.getApprovalRole(user);
        if (isRoleApproval){
            iApprovalInfoService.sendApprovalInfoToAPP(username);
        }

        map.put("accessToken",token);
        map.put("username",user.getUsername());
        map.put("idCard",user.getIdcard());
        map.put("idcardEncryption",user.getIdcardEncryption());
        map.put("IS_ROLE_APPROVAL",isRoleApproval);
        map.put("nickName",user.getNickName());
        map.put("autoUpdateUrl",type.getUpdateUrl());
        map.put("portalFrontUrl",frontUrl);
        return new ResultUtil<>().setData(map,"登录成功");
    }

    /**
     * @author    : LiYuanzhuo
     * description: 发送短信验证码
     * create time: 2019/10/14 15:09
     */
    @PostMapping(value = "/sendCode")
    @ApiOperation(value = "sendSMSCode")
    public Result<Object> sendSMSCode(@RequestParam String username){

        if (username == null) {
            return new ResultUtil<>().setErrorMsg("用户名为空！");
        }

        User user = userService.findByUsername(username);
        if (user == null){
            user = userService.findByMobile(username);
            if (user ==null) {
                return new ResultUtil<>().setErrorMsg("该用户不存在！");
            }
            List<User> userList= userDao.findByMobile(username);
            if (userList.size()>1){
                return new ResultUtil<Object>().setErrorMsg("该手机号绑定了多个账户，请使用身份证号登录！");
            }

        }

        if (user.getStatus().equals(CommonConstant.USER_STATUS_LOCK)){
            return new ResultUtil<Object>().setErrorMsg("该用户已经被禁用！请联系管理员！");
        }

        //发送验证码
        String cmsCode = CreateRandomNums.createRandomNum(6);
        SMS sms = new SMS();
        sms.setDESTADDR(user.getMobile());
        /**
         * Modify 20191225 njp 更换短信平台（发送模板短信）begin
         */
        sms.setMESSAGECONTENT("登录验证码:" + cmsCode);
        //sms.setMESSAGECONTENT(cmsCode);
        /**
         * Modify 20191225 njp 更换短信平台（发送模板短信）end
         */
        boolean sendCMSCode = callSMSservice.sendSMS(sms);

        if(sendCMSCode == false){
           return new ResultUtil<>().setErrorMsg("验证码发送失败！");
        }
        //发送成功将验证码存放到redis，以备验证
        redisTemplate = (RedisTemplate) SpringContextUtil.getBean("redisTemplate");
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);

        //验证码写死了。供测试使用，生产需要更改
        redisTemplate.opsForValue().set(CommonConstant.APP_CMS_CODE + user.getUsername(), cmsCode, 300, TimeUnit.SECONDS);
        log.info("APP用户{},手机号为{},调用发送短信验证码接口,验证码为{}",user.getUsername(),user.getMobile(),cmsCode);
        //eturn new ResultUtil<>().setSuccessMsg("验证码已发送！");
        return new ResultUtil<>().setData("验证码已发送");
    }

    /**
     * @author    : LiYuanzhuo
     * description: 获取app动态码
     * create time: 2020/1/2 15:13
     */
    @GetMapping("/getAppCode")
    public Result<Object> getAppCode(String username){
        //验证验证码
        if (!redisRepository.exists(SecurityConstant.USER_QYWX +  username)){
            return new ResultUtil<>().setErrorMsg("验证码已失效，请重新获取!");
        }
        String expireTime = stringRedisTemplate.opsForValue().get(SecurityConstant.XBOOT_USER_CODE_EXPIRE + username);
        String code = stringRedisTemplate.opsForValue().get(SecurityConstant.USER_QYWX + username);
        Map map = new HashMap();
        map.put("expireTime",expireTime);
        map.put("code",code);
        return new ResultUtil<>().setData(map);
    }
    @GetMapping("/test")
    public Result<Object> test( ){
        log.info("前端项目地址"+frontUrl);
      return  new ResultUtil<>().setData(frontUrl);
    }

}
